import math, { FIXEDINDEX } from "./math";

// 试剂架槽位名
export const ROWWORD = [
  "A",
  "B",
  "C",
  "D",
  "E",
  "F",
  "G",
  "H",
  "I",
  "J",
  "K",
  "L",
  "M",
  "N",
  "O",
  "P",
  "Q",
  "R",
  "S",
  "T",
  "U",
  "V",
  "W",
  "X",
  "Y",
  "Z",
];

// 工作台槽位名
export const RROWWORD = ["R", "S", "T", "U", "V", "W"];

// 用于修复小数计算精度的倍数
export const LARGE = 100000;

export const WIDE = 70;
export const HEIGHT = 50;
export const SPACE = 6;

export const BASEWIDE = 100;
export const BASEHEIGHT = 80;
export const RATE = 2;
export const MARGIN = 10;

export const ReactionSlotName = "C3";

// 下载文件
export const download = (filename: string, text: string) => {
  let element = document.createElement("a");
  element.setAttribute(
    "href",
    "data:text/plain;charset=utf-8," + encodeURIComponent(text)
  );
  element.setAttribute("download", filename);

  element.style.display = "none";
  document.body.appendChild(element);

  element.click();

  document.body.removeChild(element);
};

// 根据数字创建数组
export const createList = (data: number): number[] => {
  let list = [];
  for (let index = 0; index < data; index++) {
    list.push(index);
  }
  return list;
};

// 根据像素计算瓶子槽位字体大小
export const computeFontSize = (
  mmpix: number,
  diameter: number = 0
): number => {
  let size = 12;
  switch (mmpix) {
    case 2:
      size = 20;
      break;
    case 3:
      size = 32;
      break;
    case 4:
      size = 42;
      break;
    case 5:
      size = 56;
      break;
    case 6:
      size = 72;
      break;
  }
  if (diameter < 6) {
    size = 0;
  } else if (diameter > 12 && diameter < 18) {
    size = 42;
  }
  return size;
};

// 试管架试剂瓶粗细
export const coputeBorderWide = (mmpix: number): number => {
  let wide = 4;
  if (mmpix >= 4) {
    wide = 6;
  }
  return wide;
};

// 自动计算试管架试剂瓶坐标
export const computeBottleXY = ({
  row = 0,
  column = 0,
  diameter = 0,
  offsetx = 0,
  offsety = 0,
  rowSpace = 0,
  columnSpace = 0,
}: any) => {
  let list = [];
  for (let rowIndex = 0; rowIndex < row; rowIndex++) {
    for (let colIndex = 0; colIndex < column; colIndex++) {
      let offsetXLarge = offsetx * LARGE;
      let offsetYLarge = offsety * LARGE;
      let diameterLarge = diameter * LARGE;
      let rowSpaceLarge = rowSpace * LARGE;
      let columnSpaceLarge = columnSpace * LARGE;

      let autoy =
        (offsetXLarge +
          diameterLarge * rowIndex +
          columnSpaceLarge * rowIndex +
          diameterLarge / 2) /
        LARGE;

      let autox =
        (offsetYLarge +
          diameterLarge * colIndex +
          rowSpaceLarge * colIndex +
          diameterLarge / 2) /
        LARGE;

      list.push({
        name: `${ROWWORD[rowIndex]}${colIndex + 1}`,
        autox,
        autoy,
        diameter,
        rowIndex,
        colIndex,
      });
    }
  }
  return list;
};

// 自动计算工作台信息
export const computeSlot = ({
  row,
  column,
  rrow,
  rcolumn,
  slotList,
}: any): any[] => {
  const getSlotInfo = (slotName: string) => {
    let temp = null;
    if (slotList && slotList.length) {
      slotList.some((item: any) => {
        if (item.name === slotName) {
          temp = item;
          return true;
        }
        return false;
      });
    }
    return temp;
  };

  let list = [];
  for (let rowIndex = 0; rowIndex < row; rowIndex++) {
    for (let colIndex = 0; colIndex < column; colIndex++) {
      const name = `${ROWWORD[rowIndex]}${colIndex + 1}`;
      const slotInfo: any = getSlotInfo(name);
      list.push({
        name,
        x: slotInfo?.x,
        y: slotInfo?.y,
      });
    }
  }
  for (let rowIndex = 0; rowIndex < rrow; rowIndex++) {
    for (let colIndex = 0; colIndex < rcolumn; colIndex++) {
      const name = `${RROWWORD[rowIndex]}${colIndex + 1}`;
      const slotInfo: any = getSlotInfo(name);
      list.push({
        name,
        x: slotInfo?.x,
        y: slotInfo?.y,
      });
    }
  }
  return list;
};

// 创建唯一id
export const createUID = () =>
  new Date().getTime() + Math.random().toString(36).substr(8);

// 已经使用的试剂字符串
export const getUsedReagentString = ({
  mmol,
  lang,
  volume,
  weight,
}: any): string[] => {
  let amountList: string[] = [];
  if (mmol > 0) {
    amountList.push(`${mmol} ${lang["langmmol"]}`);
  }
  if (volume > 0) {
    amountList.push(`${volume} ${lang["langmlunit"]}`);
  }
  if (weight) {
    amountList.push(`${weight} ${lang["langmg"]}`);
  }

  return amountList;
};

// 生成实验反应信息
export const getReactorInfoList = ({
  lang,
  langCur,
  getReagentInfoById,
  designer,
}: any) => {
  const { reactors, temperature, reactionTime } = designer;
  // TODO 由于中文信息会导致客户端解析出错，这里都用英文
  //   langCur = "en"
  if (reactors && reactors.length) {
    let tempObj: any = {};
    reactors.forEach((item: any) => {
      const { tubeName, reagentid, mmol, volume, weight } = item;
      if (!tempObj[tubeName]) {
        tempObj[tubeName] = {};
        tempObj[tubeName]["list"] = [];
      }

      const reagentInfo = getReagentInfoById(reagentid);

      if (reagentInfo) {
        const { name, cnname } = reagentInfo;
        const amountStr = getUsedReagentString({ mmol, volume, weight, lang });

        let tempStr = `${name}(${amountStr.join(", ")})`;
        if (langCur === "zhcn" && cnname) {
          tempStr = `${cnname}(${amountStr.join(", ")})`;
        }
        tempObj[tubeName]["list"].push(tempStr);
      }
    });

    let tempList: string[] = [];
    let tubeNames = Object.keys(tempObj);
    if (tubeNames && tubeNames.length) {
      tubeNames.forEach((tubeName: string) => {
        let defaultStr = lang["langreactortip"];
        // let defaultStr = "{1} ADD {2}, STIR for {3} hours at {4} degree."

        let reagents = tempObj[tubeName]["list"].join(
          langCur === "zhcn" ? "、" : ", "
        );
        let reactorstr = defaultStr
          .replace("{1}", tubeName)
          .replace("{2}", reagents)
          .replace("{3}", reactionTime)
          .replace("{4}", temperature);
        tempList.push(reactorstr);
      });
    }
    return tempList;
  }

  return [];
};

// 根据试剂mmol计算出 weight和volume
// 如果用户输入了molar amount (mmol , 毫摩尔)，weight = mmol x (molecular weight)/percentage, Volume = weight / density /1000
interface ITWeightVolume {
  weight: number | null;
  volume: number | null;
}

interface ITMmolVolume {
  mmol: number | null;
  volume: number | null;
}

interface ITMmolWeight {
  mmol: number | null;
  weight: number | null;
}

// 根据试剂mmol计算出 weight和volume
export const getAmountByMmol = (
  mmol: number | null,
  reagent: any
): ITWeightVolume => {
  let weight = null;
  let volume = null;
  const { percentage = 100, density, mw } = reagent;
  if (mmol && reagent && density && mw) {
    const tempWeight: any = math.format(
      math.evaluate(`(${mmol} * ${mw}) / (${percentage} / 100)`),
      FIXEDINDEX
    );
    weight = tempWeight - 0;
    const tempVolume: any = math.format(
      math.evaluate(`${weight} / ${density} / 1000`),
      FIXEDINDEX
    );
    volume = tempVolume - 0;
  }
  return {
    weight,
    volume,
  };
};

// 根据试剂weight计算出 mmol和volume
export const getAmountByWeight = (
  weight: number | null,
  reagent: any
): ITMmolVolume => {
  let mmol = null;
  let volume = null;
  const { percentage = 100, density, mw } = reagent;
  if (weight && reagent && density && mw) {
    let tempMmol: any = math.format(
      math.evaluate(`(${weight} * (${percentage} / 100)) / ${mw}`),
      FIXEDINDEX
    );
    mmol = tempMmol - 0;
    let tempVomlume: any = math.format(
      math.evaluate(`${weight} / ${density} / 1000`),
      FIXEDINDEX
    );
    volume = tempVomlume - 0;
  }
  return {
    mmol,
    volume,
  };
};

// 根据试剂volume计算出 mmol和weight
export const getAmountByVolume = (
  volume: number | null,
  reagent: any
): ITMmolWeight => {
  let mmol = null;
  let weight = null;
  const { percentage = 100, density, mw } = reagent;
  if (volume && reagent && density && mw) {
    let tempWeight: any = math.format(
      math.evaluate(`${volume} * 1000 * ${density}`),
      FIXEDINDEX
    );
    weight = tempWeight - 0;
    let tempMmol: any = math.format(
      math.evaluate(`(${weight} * (${percentage} / 100)) / ${mw}`),
      FIXEDINDEX
    );
    mmol = tempMmol - 0;
  }
  return {
    mmol,
    weight,
  };
};

/**
 * 判断是固体还是液体
 * @param type string
 * @returns 0:未知  1：液体 2：固体
 */
export const getReagentType = (type: string): number => {
  let reagentType = 0;
  if (type === "tablet" || type === "powder") {
    reagentType = 2;
  } else if (type === "liquid" || type === "solution") {
    reagentType = 1;
  }
  return reagentType;
};

export const getUserInfo = () => {
  let userInfo = null;
  try {
    let userstring = sessionStorage.getItem("USERINFO") || "";
    userInfo = JSON.parse(userstring);
  } catch (e) {}
  return userInfo;
};

/**
 * 对字符串数组进行分组并重新组合 把A1,A2,B1,B2,C1,C2...重新组合为A1,B1,C1,A2,B2,C2...
 *
 * @param arr 待分组的字符串数组
 * @returns 重新组合后的字符串数组
 */
export function transformArray(arr: string[]) {
  // 创建一个对象来分组
  const groups: any = {};

  // 遍历数组，按字母分组
  arr.forEach((item: any) => {
    const key = item[0]; // 获取字母部分
    if (!groups[key]) {
      groups[key] = [];
    }
    groups[key].push(item);
  });

  // 获取分组后的数组
  const groupedArrays = Object.values(groups);

  // 重新组合数组
  const result: string[] = [];
  const maxLength = Math.max(...groupedArrays.map((arr: any) => arr.length));

  for (let i = 0; i < maxLength; i++) {
    groupedArrays.forEach((group: any) => {
      if (group[i]) {
        result.push(group[i]);
      }
    });
  }

  return result;
}

/**
 * 过滤掉对象中值为0的非对象属性以及空对象
 *
 * @param obj 需要处理的对象
 * @returns 过滤后的对象
 */
export function filterZeroAmount(obj: any) {
  // 递归终止条件：如果不是对象或数组，直接返回
  if (typeof obj !== "object" || obj === null) return obj;

  // 创建新对象用于保存处理后的结果
  const newObj: any = Array.isArray(obj) ? [] : {};

  // 遍历对象的所有键
  for (const key in obj) {
    if (Object.hasOwnProperty.call(obj, key)) {
      const value = obj[key];

      // 递归处理子对象
      const processedValue = filterZeroAmount(value);

      // 跳过处理结果为空的子对象
      if (typeof processedValue === "object" && processedValue !== null) {
        if (Object.keys(processedValue).length === 0) continue;
      }

      // 过滤值为 0 的非对象属性
      if (typeof processedValue !== "object" && processedValue === 0) continue;

      // 保留有效属性
      newObj[key] = processedValue;
    }
  }

  // 返回处理后的对象（如果是数组则转换为对象）
  return Array.isArray(newObj) && Object.keys(newObj).length === 0
    ? {}
    : newObj;
}

/**
 * 获取数组中目标元素之前元素的逆序数组
 *
 * @param arr 待查找的数组
 * @param target 目标元素
 * @returns 目标元素之前元素的逆序数组，若目标元素不存在或位于数组首位，则返回空数组
 */
export function getReversedBefore(
  arr: any,
  startElement: any,
  endElement: any
) {
  const startIndex = arr.indexOf(startElement);
  const endIndex = arr.indexOf(endElement);

  if (startIndex === -1 || endIndex === -1) {
    return [];
  }

  const start = Math.min(startIndex, endIndex);
  const end = Math.max(startIndex, endIndex);

  return arr.slice(start + 1, end + 1);
}

export function filterAndFindRemoved(reagentsort: any, defReagentList: any) {
  const defSet = new Set(defReagentList);
  const removed = [];
  const newReagentSort = [];

  for (const id of reagentsort) {
    if (defSet.has(id)) {
      newReagentSort.push(id);
    } else {
      removed.push(id);
    }
  }

  return {
    removed: removed,
    newReagentSort: newReagentSort,
  };
}

/**
 * 交换数组中指定元素的位置
 *
 * @param arr 待操作的数组
 * @param index 要交换位置的元素的索引
 * @param direction 交换的方向，'moveleft'表示向左交换，'moveright'表示向右交换
 * @returns 交换后的数组
 */
export function swapElementPosition(
  arr: any,
  index: number,
  direction: string
) {
  if (index < 0 || index > arr.length) {
    return arr;
  }

  if (direction === "moveleft") {
    if (index > 0) {
      [arr[index - 1], arr[index]] = [arr[index], arr[index - 1]];
    }
  } else if (direction === "moveright") {
    if (index === arr.length - 1) {
      arr.push(null);
    }
    [arr[index], arr[index + 1]] = [arr[index + 1], arr[index]];
  }

  return arr;
}